<template>
  <div class="task-container">
    <h1>定时任务</h1>
    <!-- 搜索栏 -->
    <div class="search-box">
    <el-row :gutter="12" align="middle"  style="margin-bottom: 10px;">
      <el-col :span="4">
        <el-input v-model="searchTaskForm.taskId" clearable placeholder="任务ID" ></el-input>
      </el-col>
      <el-col :span="4">
        <el-select v-model="searchTaskForm.className" clearable placeholder="请选择类" @change="onTaskClassChange">
          <el-option
              v-for="item in uniqueClassOptions"
              :key="item.className"
              :label="item.classLabel"
              :value="item.className"
          />
        </el-select>
      </el-col>
      <el-col :span="4">
        <el-select v-model="searchTaskForm.methodName" clearable placeholder="请选择方法">
          <el-option
              v-for="item in filteredTaskMethodOptions"
              :key="item.methodName"
              :label="item.methodLabel"
              :value="item.methodName"
          />
        </el-select>
      </el-col>
      <el-col :span="4">
        <el-select
            v-model="searchTaskForm.concurrent"
            placeholder="并发"
            clearable
            style="width: 100%"
        >
          <el-option label="允许" value=true />
          <el-option label="禁止" value=false />
        </el-select>
      </el-col>
      <el-col :span="4">
        <el-select
            v-model="searchTaskForm.status"
            placeholder="状态"
            clearable
            style="width: 100%"
        >
          <el-option label="启用" value="ENABLED" />
          <el-option label="禁用" value="DISABLED" />
        </el-select>
      </el-col>
      <el-col :span="4">
        <el-button type="primary" @click="fetch">搜索</el-button>
      </el-col>
    </el-row>
    </div>
    <!-- 顶部按钮 -->
    <div class="toolbar">
      <el-button type="primary" @click="dialog = true">新增/编辑任务</el-button>
    </div>
    <div>
    <!-- 任务列表表格 -->
    <el-table :data="tasks" border style="margin-top: 20px" class="task-table" height="350px"
              v-loading="loadingTask"
              element-loading-text="Loading..."
              :element-loading-spinner="svg"
              element-loading-svg-view-box="-10, -10, 50, 50"
              element-loading-background="rgba(122, 122, 122, 0.8)">
      <el-table-column prop="taskId" label="任务ID" />
      <el-table-column prop="cron" label="Cron表达式" :min-width="100"/>
      <el-table-column prop="className" label="执行类" :min-width="200"/>
      <el-table-column prop="methodName" label="方法名" :min-width="100"/>
      <el-table-column label="并发">
        <template #default="scope">
          <el-tag :type="scope.row.concurrent ? 'success' : 'danger'">
            {{ scope.row.concurrent ? '允许' : '禁止' }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="状态">
        <template #default="scope">
          <el-tag :type="scope.row.status === 'ENABLED' ? 'success' : 'danger'">
            {{ scope.row.status === 'ENABLED' ? '启用' : '禁用' }}
          </el-tag>
        </template>
      </el-table-column>

      <!-- 操作列宽度加宽 -->
      <el-table-column label="操作" :min-width="260">
        <template #default="scope">
          <el-button type="primary" size="small" @click="toggle(scope.row)" :loading="isRowLoading(scope.row.taskId)">
            {{ scope.row.status === 'ENABLED' ? '禁用' : '启用' }}
          </el-button>
          <el-button type="warning" size="small" @click="updateDialog(scope.row)" :loading="isRowLoading(scope.row.taskId)" >修改</el-button>
          <el-button type="danger" size="small" @click="remove(scope.row.taskId)" :loading="isRowLoading(scope.row.taskId)">删除</el-button>
          <el-button type="info" size="small" @click="fetchLogData(scope.row.taskId)" :loading="isRowLoading(scope.row.taskId)">日志</el-button>
        </template>
      </el-table-column>
    </el-table>
      <!-- 分页 -->
      <div style="display: flex; justify-content: center; padding: 16px 0">
        <el-pagination
            background
            layout="total, sizes, prev, pager, next, jumper"
            :current-page="taskPagination.currentPage"
            :page-size="taskPagination.pageSize"
            :page-sizes="[10, 20, 50, 100]"
            :total="taskPagination.total"
            @size-change="handleTaskSizeChange"
            @current-change="handleTaskPageChange"
        />
      </div>
    </div>

    <!-- 新增/编辑任务弹窗 -->
    <el-dialog v-model="dialog" :title="form.id ? '修改/编辑任务' : '新增/编辑任务'" @close="handleTaskClose">
      <el-form :model="form" label-width="100px" class="form-flex">
        <div class="form-row">
          <el-form-item label="任务ID" class="form-item">
            <el-input v-model="form.taskId" clearable :readonly="form.id?true:false"/>
          </el-form-item>

          <el-form-item label="cron表达式" class="form-item cron-input">
            <div style="display: flex; width: 100%; align-items: center;">
              <el-input
                  clearable
                  v-model="form.cron"
                  placeholder="请输入cron执行表达式"
                  style="flex: 1; margin-right: 10px;"
              />
              <el-button @click="handleShowCron">生成表达式</el-button>
            </div>
          </el-form-item>
        </div>

        <div class="form-row">
          <el-form-item label="执行类" class="form-item">
            <el-select v-model="form.className" clearable placeholder="请选择类" @change="onClassChange">
              <el-option
                  v-for="item in uniqueClassOptions"
                  :key="item.className"
                  :label="item.classLabel"
                  :value="item.className"
              />
            </el-select>
          </el-form-item>

          <el-form-item label="执行方法" class="form-item">
            <el-select v-model="form.methodName" clearable placeholder="请选择方法">
              <el-option
                  v-for="item in filteredMethodOptions"
                  :key="item.methodName"
                  :label="item.methodLabel"
                  :value="item.methodName"
              />
            </el-select>
          </el-form-item>
        </div>

        <div class="form-row">
          <el-form-item label="允许并发" class="form-item">
            <el-switch v-model="form.concurrent" active-text="是" inactive-text="否" />
          </el-form-item>
        </div>
      </el-form>

      <template #footer>
        <el-button @click="dialog = false">取消</el-button>
        <el-button type="primary" @click="save" :loading="loadingSave">保存</el-button>
      </template>
    </el-dialog>
    <el-dialog title="Cron表达式生成器" v-model="openCron" append-to-body destroy-on-close>
      <crontab ref="crontabRef" @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
    </el-dialog>
      <el-dialog :title="'任务ID：' +logName + '运行日志'" v-model="logDialog" width="80%" @close="handleClose">
        <!-- 搜索栏 -->
        <div class="search-box">
        <el-row :gutter="12" align="middle" style="margin-bottom: 5px">
          <!-- 日期范围选择器 -->
          <el-col :span="12">
            <el-date-picker
                v-model="searchForm.execTime"
                type="daterange"
                start-placeholder="开始时间"
                end-placeholder="结束时间"
                value-format="YYYY-MM-DD HH:mm:ss"
                :default-time="defaultTime"
                style="width: 100%"
            />
          </el-col>

          <!-- 状态选择器 -->
          <el-col :span="6" style="margin-bottom: 5px;margin-left: 50px">
            <el-select
                v-model="searchForm.status"
                placeholder="选择状态"
                clearable
                style="width: 100%"
            >
              <el-option label="成功" value="SUCCESS" />
              <el-option label="失败" value="FAILED" />
            </el-select>
          </el-col>
          <el-col :span="3" style="margin-bottom: 5px;">
            <el-button type="primary" @click="fetchLogData(logName)">搜索</el-button>
          </el-col>
        </el-row>
        </div>


        <el-table
              :data="logFormData"
              border
              height="300px"
              style="width: 100%"
              :row-class-name="tableRowClassName"
              v-loading="loadingLog"
              element-loading-text="Loading..."
              :element-loading-spinner="svg"
              element-loading-svg-view-box="-10, -10, 50, 50"
              element-loading-background="rgba(122, 122, 122, 0.8)"

          >
            <el-table-column prop="id" label="序号" sortable width="80" align="center" />
            <el-table-column prop="taskId" label="任务ID" width="150" align="center" />
            <el-table-column prop="className" label="执行类名" width="250" show-overflow-tooltip align="center" />
            <el-table-column prop="methodName" label="执行方法名" width="180" align="center" />
            <el-table-column prop="status" label="执行状态" width="120" align="center">
              <template #default="{ row }">
                <el-tag :type="row.status === 'SUCCESS' ? 'success' : 'danger'">
                  {{ row.status === "SUCCESS" ? '成功' : '失败' }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="execTime" label="执行时间" sortable width="180" align="center"   />
            <el-table-column prop="message" label="执行结果" min-width="180" show-overflow-tooltip align="center" />
          </el-table>

          <!-- 分页 -->
          <div style="display: flex; justify-content: center; padding: 16px 0">
            <el-pagination
                background
                layout="total, sizes, prev, pager, next, jumper"
                :current-page="logPagination.currentPage"
                :page-size="logPagination.pageSize"
                :page-sizes="[10, 20, 50, 100]"
                :total="logPagination.total"
                @size-change="handleLogSizeChange"
                @current-change="handleLogPageChange"
            />
          </div>
      </el-dialog>
  </div>
</template>
<script setup lang="ts">
import { ref, onMounted ,computed,reactive } from 'vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'
import Crontab from '@/components/Crontab/indexComponent.vue'

// 数据与状态
const tasks = ref([])
const dialog = ref(false)
const logDialog = ref(false)
const expression = ref("");
const openCron = ref(false);
const loadingSave=ref(false)
const loadingTask=ref(true)
const loadingLog=ref(true)
// 记录 loading 中的行 taskId
const loadingRows = ref(new Set<string>())
const form = ref({
  id: '',
  taskId: '',
  cron: '',
  className: '',
  methodName: '',
  concurrent: false
})
const logName = ref('')
interface logForm  {
  id:string,
  taskId:string,
  className:string,
  methodName:string,
  status:string,
  execTime:string,
  message:string
}
interface TaskOption {
  className: string,
  methodName: string,
  classLabel:string,
  methodLabel:string
}
const taskOptions = ref(<TaskOption[]>[])
const logPagination = reactive({
  currentPage: 1,
  pageSize: 10,
  total:0
})
const taskPagination=reactive({
  currentPage: 1,
  pageSize: 10,
  total:0
})
const searchForm = reactive({
  execTime: '',
  status: '',
})
const defaultTime = ref<[string, string]>([
  new Date().toISOString().slice(0, 10) + ' 00:00:00',
  new Date().toISOString().slice(0, 10) + ' 23:59:59'
])
const searchTaskForm=reactive({
    taskId:"",
    concurrent:"",
    status:"",
    className:'',
    methodName:''
})
const svg = `
        <path class="path" d="
          M 30 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 15 15
        " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
      `
const isRowLoading = (taskId: any) => {
  return loadingRows.value.has(taskId)
}
// 获取任务列表
const fetch = async () => {
  loadingTask.value=true
  try {
    const res= await axios.get('/dev-api/tasks/list', {
      params: {
        page: taskPagination.currentPage,
        size: taskPagination.pageSize,
        ...searchTaskForm
      }
    })
      tasks.value = res.data.records
      taskPagination.total = res.data.total
  }catch (e){
    ElMessage.error('获取失败')
  }finally {
    loadingTask.value=false;
  }

}


// 保存任务（新增或更新）
const save = async () => {
  if (loadingSave.value) return
  loadingSave.value=true
  try {
    if (!form.value.id) {
      const res=await axios.post('/dev-api/tasks/add', form.value)
      if(res.data==="OK"){
        ElMessage.success('新增成功')
      }else{
        ElMessage.error('新增失败')
      }
    } else {
      const res=await axios.post('/dev-api/tasks/update', form.value)
      if(res.data==="OK"){
        ElMessage.success('修改成功')
      }else{
        ElMessage.error('修改失败')
      }
    }
  } catch (e) {
    ElMessage.error('操作失败')
  } finally {
    dialog.value = false
    await fetch()
    loadingSave.value=false
  }


}


// 删除任务
const remove = async (id:any) => {
  if (isRowLoading(id)) return
      loadingRows.value.add(id)
  try {
      const res =await axios.post('/dev-api/tasks/remove', null, { params: { taskId: id } })
      if(res.data==="OK"){
        ElMessage.success('删除成功')
      }else{
        ElMessage.error('删除失败')
      }
  } catch (e) {
       ElMessage.error('操作失败')
  } finally {
      await fetch()
    loadingRows.value.delete(id)

  }
}

// 启用或禁用任务切换
const toggle = async (row:any) => {
  if (isRowLoading(row.taskId)) return
  loadingRows.value.add(row.taskId)
  try {
    const url = row.status === 'ENABLED' ? '/dev-api/tasks/pause' : '/dev-api/tasks/resume'
    const res = await axios.post(url, null, {params: {taskId: row.taskId}})
      if (res.data === "OK") {
        row.status === 'ENABLED' ? ElMessage.success('禁用成功') : ElMessage.success('启用成功')
      } else {
        row.status === 'ENABLED' ? ElMessage.error('禁用失败') : ElMessage.error('启用失败')
      }
  }catch (e) {
      ElMessage.error('操作失败')
    } finally {
      await fetch()
    loadingRows.value.delete(row.taskId)
  }
}
// 打开编辑弹窗
const updateDialog = (row:any) => {
  form.value = { ...row }
  dialog.value = true
}
/** cron表达式按钮操作 */
function handleShowCron() {
  expression.value = form.value.cron;
  openCron.value = true;
}
/** 确定后回传值 */
function crontabFill(value:any) {
  form.value.cron = value;
}


const uniqueClassOptions = computed(() => {
  const seen = new Set()
  return taskOptions.value.filter(item => {
    if (!seen.has(item.className)) {
      seen.add(item.className)
      return true
    }
    return false
  })
})

const filteredMethodOptions = computed(() =>
    taskOptions.value.filter(item => item.className === form.value.className)
)
const filteredTaskMethodOptions = computed(() =>
    taskOptions.value.filter(item => item.className === searchTaskForm.className)
)

const fetchTaskOptions = async () => {
  try {
    const res = await axios.get('/dev-api/task-meta/list')
    taskOptions.value = res.data
  } catch (err) {
    console.error('获取任务方法失败', err)
  }
}

const onClassChange = () => {
  form.value.methodName = ''
}
const onTaskClassChange = () => {
  searchTaskForm.methodName = ''
}

const tableRowClassName = ({ row }: { row: logForm }) => {
  return row.status === 'FAILED' ? 'warning-row' : 'success-row'
}
const logFormData=ref(<logForm[]>[
  //   {id:'1',
  //     taskId:"1",
  //     className:"1",
  //     methodName:"1",
  //     status:"SUCCESS",
  //     execTime:"2025-07-23",
  //     message:"1"
  //   },
  // {id:'1',
  //   taskId:"1",
  //   className:"1",
  //   methodName:"1",
  //   status:"FAILED",
  //
  //   execTime:"2025-07-26",
  //   message:"1"
  // },
  // {id:'1',
  //   taskId:"1",
  //   className:"1",
  //   methodName:"1",
  //   status:"SUCCESS",
  //   execTime:"2025-07-25",
  //   message:"1"
  // },
  // {id:'1',
  //   taskId:"1",
  //   className:"1",
  //   methodName:"1",
  //   status:"SUCCESS",
  //   execTime:"2025-07-25",
  //   message:"1"
  // }
])
const fetchLogData =async(taskId:any) => {
  logDialog.value=true
  loadingLog.value=true
  logName.value =  taskId
  try {
    const res= await axios.get('/dev-api/tasks/taskLogs', {
      params: {
        page: logPagination.currentPage,
        size: logPagination.pageSize,
        taskId: taskId,
        startTime: searchForm.execTime?.[0] || defaultTime.value[0],
        endTime: searchForm.execTime?.[1] || defaultTime.value[1],
        status: searchForm.status
      }

    })
      logFormData.value = res.data.records
      logPagination.total = res.data.total
  }catch (e) {
    ElMessage.error("获取失败")
  }finally {
    loadingLog.value=false
  }

}

function handleLogSizeChange(size:any) {
  logPagination.pageSize = size
  logPagination.currentPage = 1
  fetchLogData(logName.value)
}

function handleLogPageChange(page:any) {
  logPagination.currentPage = page
  fetchLogData(logName.value)
}
function handleTaskSizeChange(size:any) {
  logPagination.pageSize = size
  logPagination.currentPage = 1
  fetch()
}

function handleTaskPageChange(page:any) {
  logPagination.currentPage = page
  fetch()
}
const handleClose = () => {
  logFormData.value=[]
  logPagination.total=0
  searchForm.execTime=''
  searchForm.status=''

}
const handleTaskClose = () => {
        form.value. id= '',
        form.value. taskId= '',
        form.value.cron= '',
        form.value. className= '',
        form.value. methodName= '',
        form.value. concurrent= false
}
// const filteredData = computed(() => {
//   return logFormData.value.filter(item => {
//     const { execTime, status } = item
//
//     // 判断执行时间是否在时间范围内
//     let execTimeMatch = true
//     if (searchForm.execTime && searchForm.execTime.length === 2) {
//       const [start, end] = searchForm.execTime
//       const execTimeDate = new Date(execTime)
//       const startDate = new Date(start)
//       const endDate = new Date(end)
//       execTimeMatch = execTimeDate >= startDate && execTimeDate <= endDate
//     }
//
//     // 状态匹配
//     const statusMatch = searchForm.status ? status === searchForm.status : true
//
//     return execTimeMatch && statusMatch
//   })
// })

// // 分页数据
// const paginatedData = computed(() => {
//   const start = (logPagination.currentPage - 1) * logPagination.pageSize
//   const end = start + logPagination.pageSize
//   //return filteredData.value.slice(start, end)
//   return logFormData.value.slice(start,end)
// })
// 初始化
onMounted(() => {
      fetch(),
      fetchTaskOptions()
})
</script>

<style scoped>
.task-container {
  width: 90%;
  max-width: 1200px;
  margin: 0 auto;
}

.toolbar {
  display: flex;
  justify-content: flex-start;
  margin-bottom: 20px;
}

.task-table {
  width: 100%;
}

.el-dialog {
  width: 60%;
  max-width: 800px;
}

@media (max-width: 768px) {
  .el-dialog {
    width: 90%;
  }
}

/* 表单 Flex 布局 */
.form-flex {
  width: 100%;
}

.form-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.form-item {
  flex: 0 0 48%;
  box-sizing: border-box;
  margin-bottom: 16px;
}

/* Cron 输入区域按钮布局 */
.cron-input {
  display: flex;
  align-items: center;
}

@media (max-width: 768px) {
  .form-item {
    flex: 0 0 100%;
  }

  .cron-input {
    flex-direction: column;
    align-items: stretch;
  }

  .cron-input .el-button {
    margin-top: 10px;
    width: 100%;
  }
}
::v-deep(.warning-row) {
  background-color: #dcb90b !important;
}
::v-deep(.success-row) {
  background-color: #9ff544 !important;
}
/* 表头背景色加深 + 字体加粗 */
::v-deep(.el-table thead) {
  background-color: #f5f7fa;
}

::v-deep(.el-table thead th) {
  background-color: #e0e6ed !important;
  color: #333 !important;
  font-weight: bold;
}
.demo-date-picker {
  display: flex;
  width: 100%;
  padding: 0;
  flex-wrap: wrap;
}
.demo-date-picker .block {
  padding: 30px 0;
  text-align: center;
  border-right: solid 1px var(--el-border-color);
  flex: 1;
}
.demo-date-picker .block:last-child {
  border-right: none;
}
.search-box {
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  padding: 16px 20px;
  margin-bottom: 20px;
  background-color: #e0e6ed;
}
.example-showcase .el-loading-mask {
  z-index: 9;
}
</style>